/**
 * 抓包器工作线程序,完成抓包工作.
 * @copyright Copyright (c) 2006 - 2007 (www.wanguangming.com)
 * @author 万光明 webmaster@wanguangming.com
 * @package Core
 * @version $Id: WorkerThread.cpp 742 2007-02-14 20:50:52Z netwan $
 */
//---------------------------------------------------------------------------
#include "PubDefine.h"
#include "core_hander.h"
#include "WorkerThread.h"
#include <map>
#include <pcap.h>
#include "global.h"
#include <QMap>
#include<stdlib.h>

TWorkerThread* g_thread;
extern void Makehashkey(const nodedata* node,char* out);
extern u_long iptoul(const ip_address ipaddress);
extern pcap_t * g_adhandle;
extern int g_NICIndex;
extern char* g_FilterString;
extern int g_packsCount,g_threadCount;
extern long g_CapBuffer;
extern QList<const nodedata*> g_node_lists;
extern QMap<QString,nodedata *> g_RootNodesHashMap;
void TWorkerThread::packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
	nodedata* node;
	struct tm *ltime;
	char timestr[16]="";
    ether_header* eh;
    pp_header* pph;
    ip_header *ih;
    udp_header *uh;
    tcp_header *th;
	u_int ip_len,tcp_len;
	u_short sport,dport;
	/* convert the timestamp to readable format */
	nodedata* newnode = new nodedata;
    newnode->pppoe_flag=false;
    newnode->ip_flag=false;
    newnode->udp_flag=false;
    newnode->tcp_flag=false;
    newnode->srcpacksize = 0;
    newnode->datasize = 0;
    newnode->listitemindex = -1;
	g_packsCount ++;
	//packscount++;
	time_t t=time(NULL);
	t = header->ts.tv_sec;
	ltime=  localtime(&t);
    strftime( timestr, sizeof timestr, "%H:%M:%S", ltime);
    char stime[255]="";
	char headerlen[255]="";

    //char src[255];
    //char dst[255];
    sprintf(stime,"%s %d", timestr, header->ts.tv_usec/1000);
    sprintf(headerlen,"%d",header	);
    eh =(ether_header *)pkt_data;
	if (eh->ether_type ==htons(ETHERTYPE_IP))
    {
    newnode->ip_flag =true;
    }
    else if(eh->ether_type ==htons(ETHERTYPE_PPPOE_SESSION))
    {
      newnode->pppoe_flag =true;
      pppoeheader* ph = (pppoeheader*)(pkt_data +ETHER_HDRLEN);
      pph = (pp_header *) ((u_char*)pkt_data +
         ETHER_HDRLEN + (newnode->pppoe_flag ? 6 :0));
     /* retireve the position of the ip header */

      if (pph->proto == htons(0x0021))  //0x0021 internet protocol
      {
	   newnode->ip_flag =true;
      }
	}
	 ih = (ip_header *) ((u_char*)pkt_data +
         ETHER_HDRLEN + (newnode->pppoe_flag ? 6 + 2:0));

     /* retireve the position of the udp header */
	 ip_len = (ih->ver_ihl & 0xf) * 4;
	 newnode->ip_header_len = ip_len;
     if(ih->proto ==IPPROTO_TCP)
     {
     th = (tcp_header *) ((u_char*)ih + ip_len );
	 tcp_len = (th->th_lenres >> 4) * 4;
     newnode->tcp_header_len = tcp_len;
     /* convert from network byte order to host byte order */
     sport = ntohs( th->sport );
     dport = ntohs( th->dport );
     }
     if(ih->proto ==IPPROTO_UDP || ih->proto ==IPPROTO_ICMP)
	 {
     uh = (udp_header *) ((u_char*)ih + ip_len );
	 newnode->udp_header_len = UDP_HDRLEN;

     /* convert from network byte order to host byte order */
     sport = ntohs( uh->sport );
     dport = ntohs( uh->dport );
     }

    strcpy(newnode->starttime,stime);
    if(newnode->ip_flag)
    {
    newnode->srcip.byte1 = ih->saddr.byte1;
    newnode->srcip.byte2 = ih->saddr.byte2;
    newnode->srcip.byte3 = ih->saddr.byte3;
    newnode->srcip.byte4 = ih->saddr.byte4;

    newnode->sport = sport;

    newnode->dstip.byte1 = ih->daddr.byte1;
    newnode->dstip.byte2 = ih->daddr.byte2;
    newnode->dstip.byte3 = ih->daddr.byte3;
    newnode->dstip.byte4 = ih->daddr.byte4;
    newnode->dport =dport;

    newnode->proto = ih->proto;
    }
    else
    {

    newnode->srcip.byte1 = 0x00;
    newnode->srcip.byte2 = 0x00;
    newnode->srcip.byte3 = 0x00;
    newnode->srcip.byte4 = 0x00;

    newnode->sport = 0x00;
    newnode->dstip.byte1 = 0x00;
    newnode->dstip.byte2 = 0x00;
    newnode->dstip.byte3 = 0x00;
    newnode->dstip.byte4 = 0x00;
    newnode->dport = 0x00;
    if (htons(eh->ether_type) ==ETHERTYPE_ARP)
    newnode->proto = EARP;
    }

    if(!newnode->ip_flag) //不抓非ip协议的包
	{
    delete newnode;
    return;
	}
	char nodehashkey[45];
	Makehashkey(newnode,nodehashkey);
	dump(stdout,"HashKey:%s",nodehashkey);
	newnode->packscount =1;
    newnode->listitemindex =-1;
	g_CapBuffer += header->caplen;
	newnode->header = new pcap_pkthdr();
	memcpy(newnode->header,header,sizeof(pcap_pkthdr));
	newnode->srcpackdata = malloc( header->caplen);
    memcpy(newnode->srcpackdata,pkt_data,header->caplen);

	newnode->srcpacksize = header->caplen;
    if(ih->proto == IPPROTO_TCP)
    {
    newnode->datasize = header->caplen - 14 - 20 - newnode->tcp_header_len - (newnode->pppoe_flag ? 8:0);
	newnode->tcp_flag =true;
    }
    if(ih->proto == IPPROTO_UDP)
    {
    newnode->datasize = header->caplen - 14 -20 - newnode->udp_header_len - (newnode->pppoe_flag ? 8:0);
    newnode->udp_flag = true;
	}

	g_node_lists.push_back(newnode);
	QMap<QString, nodedata *>::iterator it = g_RootNodesHashMap.find((QString)nodehashkey);
	bool isfirstin=false;
	
	if(it != g_RootNodesHashMap.end())//握手过的包
	{
		dump(stdout,"old packet:key=%s", nodehashkey);
		nodedata* found_node = (nodedata*)it.value();
		int forword = iptoul(found_node->srcip) == iptoul(newnode->srcip) ? 0 : 1;
		newnode->up_or_down =  forword ;
		newnode->listitemindex = found_node->listitemindex;
		dump(stdout,"old node->listitemindex:%d", found_node->listitemindex);
		found_node->packscount ++;
		
		strcpy(found_node->lasttime , newnode->starttime);
		found_node->childs.push_back(newnode);
		g_packsCount ++;
		isfirstin = false;
		node = found_node;
	}
	else//处女包
	{

		dump(stdout,"first packet:key=%s", nodehashkey);
		newnode->up_or_down =0; //发送
		g_RootNodesHashMap[(QString)nodehashkey] = newnode;
		g_threadCount ++;
		isfirstin = true;
		node = newnode;
	}
	node->isroot = isfirstin;
	emit g_thread->CatchPACKET(node);
	
}
TWorkerThread::TWorkerThread()
{
}
//---------------------------------------------------------------------------
void TWorkerThread::run()
{
	emit OpenDevice();
	int waittime=0;
	while(g_adhandle==0)
	{
		this->sleep(1);
		waittime++;
		if(waittime>40){
			this->ShowError("Open device fair!time out in 20 sec.");
		}
	}
	if(g_adhandle)
	{
		DoWatch();
	}
	//---- Place thread code here ----
}
//---------------------------------------------------------------------------
void TWorkerThread::DoWatch()
{
	
	if(g_adhandle)
    {    
         emit OnStartCat();
         pcap_loop(g_adhandle, 0, TWorkerThread::packet_handler, NULL);
         pcap_close(g_adhandle);
         
    }
    else
    {
        ShowError("Open interfaces faire! Make sure WinPcap is installed.");
		return ;
    }
}
//---------------------------------------------------------------------------
void TWorkerThread::StopCap()
{
	pcap_breakloop(g_adhandle);
}
